const c = document.getElementById('c'),
      ctx = c.getContext('2d'),
      f = document.getElementById('chooseFile')

let file = null,
    frameId = null,
    timer = null,
    time = 0,
    audioBufferSouceNode = null,
    audioAnalyser = null, // 音频分析器
    audioContext = null; // 音频上下文，用于解码 ArrayBuffer

const meterNum = innerWidth / (10 + 2)
      meterWidth = 10,
      capHeight = 2;

const render = () => {
  const array = new Uint8Array(audioAnalyser.frequencyBinCount);
  audioAnalyser.getByteFrequencyData(array);
  const step = Math.round(array.length / meterNum); //计算采样步长
  for (let i = 0; i < meterNum; i++) {
    const value = array[i * step]; //获取当前能量值
    ctx.fillRect(i * 12, c.height - value + capHeight, meterWidth, c.height);
  }
}

const animate = () => {
  frameId = requestAnimationFrame(animate);
  ctx.clearRect(0, 0, c.width, c.height);
  render();
}

// 通过分析数据绘制频谱图，启动绘制
const drawAnalyser = (array) => {
  const gradient = ctx.createLinearGradient(0, 0, c.width, c.height);
  gradient.addColorStop(1, '#0f0');
  gradient.addColorStop(0.5, '#ff0');
  gradient.addColorStop(0, '#f00');
  ctx.fillStyle = gradient;
  timer = setInterval(() => {
    time += 1;
    if (time > +audioBufferSouceNode.buffer.duration + 2) {
      console.log('end');
      if (timer) clearInterval(timer);
      if (frameId) cancelAnimationFrame(frameId);
    }
  }, 1000);
  render(array);
  console.log('start');
  animate();
}

// 音频解码数据成功
const handleDecodeDataSuccess = (buffer) => {
  console.log(buffer); // 解码后的音频缓存

  // 将音频缓存赋值到音频上下文容器（音频资源节点对象
  audioBufferSouceNode = audioContext.createBufferSource();
  audioBufferSouceNode.buffer = buffer;

  // 创建一个音频分析器
  audioAnalyser = audioContext.createAnalyser();

  // 为了在音频输出到扬声器前捕捉到音频数据，需要将一个分析器插入到资源节点和扬声器之间
  audioBufferSouceNode.connect(audioAnalyser);

  // 仅仅播放还听不到声音，需要先将音频对接到扬声器
  audioAnalyser.connect(audioContext.destination); // destination 与扬声器相关

  // 此时可以开始音频播放
  audioBufferSouceNode.start(0);
  console.log(audioBufferSouceNode);

  // 此时便可以通过音频分析器获取频率信息
  console.log(audioAnalyser);
  /**
   * 频谱反映的是声音各频率上的能量分布，是通过将输入声音数字信号经过傅里叶变化得到的
   * AnalyserNode {
   *  channelCount: 2 通道数
      channelCountMode: "max"
      channelInterpretation: "speakers"
      context: AudioContext {baseLatency: 0.01, destination: AudioDestinationNode, currentTime: 15.690666666666667, sampleRate: 48000, listener: AudioListener, …}
      fftSize: 2048 一个无符号的长整型数字，表示一个FFT（快速傅里叶变换）的大小，用于确定频率域
      frequencyBinCount: 1024 fftSize 的一遍，基本等于要播放数据量
      maxDecibels: -30 概念同下，显然是返回的最大值
      minDecibels: -100 双进度值，表示FFT分析数据缩放范围内的最小功率值，基本上就是 getByteFrequencyData() 返回的最小值
      numberOfInputs: 1
      numberOfOutputs: 1
      smoothingTimeConstant: 0.8 最后一个分析帧的平均常数，它使值之间的转换随时间推移更平滑
   * }
   */

  // 通过 frequencyBinCount 和 AnalyserNode 下的两种种方法可以获取到各频率下能量值的分布
  const array = new Uint8Array(audioAnalyser.frequencyBinCount);
  audioAnalyser.getByteFrequencyData(array);
  /**
   * getFloatFrequencyData, getByteFrequencyData 分别拷贝频谱数据到 Float32Array，Uint8Array
   * getFloatTimeDomainData, getByteTimeDomainData 则是拷贝波形数据
   */

  drawAnalyser(array);
}

// 处理文件读取完成，获取 arrayType 数据
const handleFileReaded = (e) => {
  const fileResult = e.target.result;
  audioContext = new AudioContext();
  audioContext.decodeAudioData(fileResult, handleDecodeDataSuccess, (e) => { console.error(e); alert('解码数据失败'); });
}

// 处理文件选择
const handleFileChoose = () => {
  file = f.files[0];
  const fr = new FileReader();
  fr.onload = handleFileReaded;
  fr.readAsArrayBuffer(file); // 将文件数据转化成 ArrayBuffer 数据
}

f.addEventListener('change', handleFileChoose, false);


const handleWindowResize = () => {
  c.width = innerWidth * devicePixelRatio;
  c.height = innerHeight * devicePixelRatio;
}
handleWindowResize();
window.addEventListener('resize', handleWindowResize, false);